using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;

namespace PHSRAG.WebControls
{
	/// <summary>
	/// Provides 3 textboxes for entering the area code, exchange, and phone number that make up
	/// a telephone number.  Includes functionality to validate whether the numbers are valid numeric
	/// expressions.  If required, provides functionality to validate whether a number has been supplied.
	/// </summary>
	[ToolboxData("<{0}:TelephoneNumber runat=\"server\"></{0}:TelephoneNumber>")]
	public class TelephoneNumber : System.Web.UI.WebControls.WebControl, INamingContainer
	{
		private Label label;
		private TextBox areaCode;
		private TextBox exchange;
		private TextBox phone;

		private RegularExpressionValidator areaCodeValidator;
		private RegularExpressionValidator exchangeValidator;
		private RegularExpressionValidator phoneValidator;

		private RequiredFieldValidator areaCodeRequiredFieldValidator;
		private RequiredFieldValidator exchangeRequiredFieldValidator;
		private RequiredFieldValidator phoneRequiredFieldValidator;

		private const string PromptKey = "telephoneNumberPrompt_DD27AFAF-F5EA-4d1b-AE87-E6D021845E85";
		private const string RequiredKey = "telephoneNumberRequired_DD27AFAF-F5EA-4d1b-AE87-E6D021845E85";

		/// <summary>If required, sets up required field validators for all 3 textboxes</summary>
		[Category("Action"), Description("Causes the TelephoneNumber to be invalid if no data is entered for all 3 fields")]
		public bool Required
		{ 
			get { object o = ViewState[RequiredKey]; return (o == null) ? false : (bool)o; }
			set { ViewState[RequiredKey] = value; }
		}

		/// <summary>
		/// Gets/Sets the label that appears preceding the text boxes
		/// </summary>
		[Category("Appearance"), Description("Sets the label that precedes the text boxes")]
		public string Prompt
		{ 
			get { object o = ViewState[PromptKey]; return (o == null) ? "Telephone: " : (string)o; }
			set { ViewState[PromptKey] = value; }
		}
		/// <summary>
		/// The area code input by the user
		/// </summary>
		public string AreaCode { get { EnsureChildControls(); return areaCode.Text; } }

		/// <summary>
		/// The exchange input by the user
		/// </summary>
		public string Exchange { get { EnsureChildControls(); return exchange.Text; } }

		/// <summary>
		/// The phone number input by the user
		/// </summary>
		public string Phone { get { EnsureChildControls(); return phone.Text; } }

		/// <summary>
		/// Resets the textboxes' text to empty strings
		/// </summary>
		public void Reset() 
		{
			EnsureChildControls();
			areaCode.Text = exchange.Text = phone.Text = string.Empty;
		}

		#region Overrides

		/// <summary>
		/// Create all controls that will be in the TelephoneNumber. The creation is more than just instantiating
		/// the controls. It also involves generating the underlying HTML so that the controls shows up per the need.
		/// </summary>
		protected override void CreateChildControls()
		{
			Controls.Clear();

			label = new Label();
			label.ID = "label";
			label.Text = (Required) ? string.Format("*{0}", Prompt): Prompt;
			
			areaCode = new TextBox();
			areaCode.MaxLength = 3;
			areaCode.Columns = 3;
			areaCode.ID = "areaCode";

			exchange = new TextBox();
			exchange.Columns = 3;
			exchange.MaxLength = 3;
			exchange.ID = "exchange";

			phone = new TextBox();
			phone.Columns = 4;
			phone.MaxLength = 4;
			phone.ID = "phone";

			CreateRegExValidators();
			if (Required) CreateRequiredFieldValidators();

			GenerateControlTree();
		}
		#endregion

		/// <summary>
		/// Creates the required field validators for all 3 textboxes
		/// </summary>
		private void CreateRequiredFieldValidators()
		{
			areaCodeRequiredFieldValidator = new RequiredFieldValidator();
			exchangeRequiredFieldValidator = new RequiredFieldValidator();
			phoneRequiredFieldValidator = new RequiredFieldValidator();

			areaCodeRequiredFieldValidator.Display = exchangeRequiredFieldValidator.Display = phoneRequiredFieldValidator.Display = ValidatorDisplay.None;

			areaCodeRequiredFieldValidator.ControlToValidate = areaCode.ID;
			areaCodeRequiredFieldValidator.ErrorMessage = "Area Code is required";

			exchangeRequiredFieldValidator.ControlToValidate = exchange.ID;
			exchangeRequiredFieldValidator.ErrorMessage = "Exchange is required";

			phoneRequiredFieldValidator.ControlToValidate = phone.ID;
			phoneRequiredFieldValidator.ErrorMessage = "Phone number is required";
		}

		/// <summary>
		/// Creates the regular expression validators for all 3 textboxes
		/// </summary>
		private void CreateRegExValidators()
		{
			areaCodeValidator = new RegularExpressionValidator();
			areaCodeValidator.Display = ValidatorDisplay.None;
			areaCodeValidator.ValidationExpression = @"^\d{3}$";
			areaCodeValidator.ControlToValidate = areaCode.ID;
			areaCodeValidator.ErrorMessage = "Please enter a valid area code";

			exchangeValidator = new RegularExpressionValidator();
			exchangeValidator.Display = ValidatorDisplay.None;
			exchangeValidator.ValidationExpression =  @"^\d{3}$";
			exchangeValidator.ControlToValidate = exchange.ID;
			exchangeValidator.ErrorMessage = "Please enter a valid exchange";

			phoneValidator = new RegularExpressionValidator();
			phoneValidator.Display = ValidatorDisplay.None;
			phoneValidator.ValidationExpression =  @"^\d{4}$";
			phoneValidator.ControlToValidate = phone.ID;
			phoneValidator.ErrorMessage = "Please enter a valid phone number";
		}

		/// <summary>
		/// Setup the control tree to reflect the actual (and exact) layout of the controls within the TelephoneTextBox.
		/// </summary>
		private void GenerateControlTree()
		{
			Table table = new Table();
			Controls.Add(table);

			TableRow row = new TableRow();
			table.Rows.Add(row);

			TableCell c1 = new TableCell();
			c1.Controls.Add(label);
			row.Cells.Add(c1);

			TableCell c2 = new TableCell();
			c2.Controls.Add(areaCode);
			row.Cells.Add(c2);			

			TableCell c3 = new TableCell();
			c3.Controls.Add(exchange);
			c3.Controls.Add(new LiteralControl(" - "));
			row.Cells.Add(c3);

			TableCell c4 = new TableCell();
			c4.Controls.Add(phone);

			c4.Controls.Add(areaCodeValidator);
			c4.Controls.Add(exchangeValidator);
			c4.Controls.Add(phoneValidator);
			
			if (Required)
			{
				c4.Controls.Add(areaCodeRequiredFieldValidator);
				c4.Controls.Add(exchangeRequiredFieldValidator);
				c4.Controls.Add(phoneRequiredFieldValidator);
			}

			row.Cells.Add(c4);
		}

		#region Internal Methods
		/// <summary>
		/// This method is ONLY invoked by the associated designer to show the control contents at design time.
		/// </summary>
		internal void Design()
		{
			EnsureChildControls();
		}
		#endregion

		#region Class TelephoneNumberDesigner
		/// <summary>
		/// Designer associated with the TelephoneNumber control.
		/// </summary>
		/// <remarks>
		/// This class cannot be used directly.
		/// </remarks>
		public class TelephoneNumberDesigner : ControlDesigner
		{
			#region Overrides
			/// <summary>
			/// Force the TelephoneTextBox control to create its child controls for display at design time.
			/// </summary>
			/// <returns>HTML representation of the TelephoneTextBox control</returns>
			public override string GetDesignTimeHtml()
			{
				((TelephoneNumber)Component).Design();
				return base.GetDesignTimeHtml();
			}
			#endregion
		}
		#endregion
	}
}
